<!-- d3js 气泡图 -->
<template>
    <div id="bubble"></div>
</template>

<script setup lang="ts">
import * as echarts from 'echarts/core';
import {
    DatasetComponent,
    TooltipComponent,
    VisualMapComponent
} from 'echarts/components';
import { CustomChart } from 'echarts/charts';
import { CanvasRenderer } from 'echarts/renderers';
echarts.use([
    DatasetComponent,
    TooltipComponent,
    VisualMapComponent,
    CustomChart,
    CanvasRenderer
]);
import * as d3 from 'd3';
import { onMounted } from 'vue';

let option = {}
let colorList = ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc', '#4C6EF5', '#BE4BDB', '#FA5252', '#40C057', '#FAB005', '#FD7E14']

const props = defineProps({
    data: {
        type: Array,
        default: () => []
    }
})
let seriesData = props.data
let displayRoot = stratify1();
function stratify1() {
    return d3
        .stratify()
        .parentId(function (d) {

            return d.id.substring(0, d.id.lastIndexOf('.'));
        })(seriesData)
        .sum(function (d) {

            return d.value || 0;
        })
        .sort(function (a, b) {
            return b.value - a.value;
        });
}
function overallLayout(params, api) {

    let context = params.context;
    d3
        .pack()
        .size([api.getWidth() - 2, api.getHeight() - 2])
        .padding(5)(displayRoot);
    context.nodes = {};

    displayRoot.descendants().forEach(function (node) {

        context.nodes[node.id] = node;
    });
}
function renderItem(params, api) {
    let context = params.context;
    let idx = params.dataIndex;

    // Only do that layout once in each time `setOption` called.
    // 每次调用“setOption”时，只能进行一次布局。
    if (!context.layout) {
        context.layout = true;

        overallLayout(params, api);
    }

    let nodePath = api.value('id');
    let nodeName = nodePath
        .slice(nodePath.lastIndexOf('.') + 1)
        .split(/(?=[A-Z][^A-Z])/g)
        .join('\n')
    let node = context.nodes[nodePath];
    if (node.id === 'option') {
        node.r = 0
    }
    if (!node) {
        // Reder nothing.
        return;
    }

    let z2 = api.value('depth') * 2;
    return {
        type: 'circle',
        shape: {
            cx: node.x,
            cy: node.y,
            r: node.r
        },
        // transition: ['shape'],
        z2: z2,
        textContent: {
            type: 'text',
            style: {
                // transition: isLeaf ? 'fontSize' : null,
                text: nodeName,
                fill: '#fff',
                fontFamily: 'Arial',
                width: node.r * 1.3,
                overflow: 'truncate',
                fontSize: node.r / 3
            },
            emphasis: {
                style: {
                    overflow: null,
                    fontSize: Math.max(node.r / 3, 12)
                }
            }
        },
        textConfig: {
            position: 'inside'
        },
        style: {
            fill: colorList[idx % colorList.length]
        },
        emphasis: {
            style: {
                fontFamily: 'Arial',
                fontSize: 12,
                shadowBlur: 20,
                shadowOffsetX: 3,
                shadowOffsetY: 5,
                shadowColor: 'rgba(0,0,0,0.3)'
            }
        }
    };
}
option = {
    dataset: {
        source: seriesData
    },
    tooltip: {},
    hoverLayerThreshold: Infinity,
    series: [{
        type: 'custom',
        colorBy: 'data',
        renderItem: renderItem,
        progressive: 0,
        coordinateSystem: 'none',
        encode: {
            tooltip: 'msg',
            // itemName: 'id'
        }
    }]
}
onMounted(() => {
    initEcharts()
})

function initEcharts() {
    let myChart = echarts.init(document.getElementById('bubble'))
    myChart.setOption(option)
}
</script>
<style>
#bubble {
    min-width: 1280px;
    height: 720px;
}
</style>